﻿using System;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace ncp.Business
{
    public class EncryptHelper
    {
        #region "member fields"
        //加密种子
        private const string Iv = "6Nl_AnG0";
        //加密密匙
        private static string _key = "5D6_3Uas";
            private static Encoding _encoding = new UnicodeEncoding();
            private static readonly DES DES;
            private static readonly MD5 MD5;
            #endregion

            
            /// <summary>
            /// 构造函数
            /// </summary>
            static EncryptHelper()
            {
                DES = new DESCryptoServiceProvider();
                MD5 = new MD5CryptoServiceProvider();
            }
            #region "propertys"

            /// <summary>
            /// 设置加密密钥
            /// </summary>
            public static string EncryptKey
            {
                get { return _key; }
                set
                {
                    _key = value;
                }
            }
            /// <summary>
            /// 要加密字符的编码模式
            /// </summary>
            public static Encoding EncodingMode
            {
                get { return _encoding; }
                set { _encoding = value; }
            }
            #endregion

            #region "methods"

            /// <summary>

            /// 加密字符串并返回加密后的结果
            /// </summary>
            /// <param name="str"></param>
            /// <returns></returns>
            public static string EncryptString(string str)
            {
//                var des = new DESCryptoServiceProvider();
                byte[] inputByteArray = Encoding.Default.GetBytes(str);
                DES.Key = Encoding.ASCII.GetBytes(EncryptKey);
                DES.IV = Encoding.ASCII.GetBytes(Iv);
	            var ms = new MemoryStream();
                var cs = new CryptoStream(ms, DES.CreateEncryptor(), CryptoStreamMode.Write);
	            cs.Write(inputByteArray, 0, inputByteArray.Length);
	            cs.FlushFinalBlock();
	            var ret = new StringBuilder();
	            foreach (byte b in ms.ToArray())
	            {
	                ret.AppendFormat("{0:X2}", b);
	            }
	            return ret.ToString();
            }

            /// <summary>
            /// 加密指定的文件,如果成功返回True,否则false
            /// </summary>
            /// <param name="filePath">要加密的文件路径</param>
            /// <param name="outPath">加密后的文件输出路径</param>
            public static void EncryptFile(string filePath, string outPath)
            {
                bool isExist = File.Exists(filePath);
                if (isExist)//如果存在
                {
                    byte[] ivb = Encoding.UTF8.GetBytes(Iv);
                    byte[] keyb = Encoding.UTF8.GetBytes(EncryptKey);
                    //得到要加密文件的字节流

                    var fin = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                    var reader = new StreamReader(fin, EncodingMode);
                    string dataStr = reader.ReadToEnd();
                    byte[] toEncrypt = EncodingMode.GetBytes(dataStr);
                    fin.Close();

                    var fout = new FileStream(outPath, FileMode.Create, FileAccess.Write);
                    ICryptoTransform encryptor = DES.CreateEncryptor(keyb, ivb);
                    var csEncrypt = new CryptoStream(fout, encryptor, CryptoStreamMode.Write);
                    try
                    {
                        //加密得到的文件字节流
                        csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
                        csEncrypt.FlushFinalBlock();
                    }
                    catch (Exception err)
                    {
                        throw new ApplicationException(err.Message);
                    }
                    finally
                    {
                        fout.Close();
                        csEncrypt.Close();
                    }
                }
                else
                {
                    throw new FileNotFoundException("没有找到指定的文件");
                }
            }
            /// <summary>
            /// 文件加密函数的重载版本,如果不指定输出路径,
            /// 那么原来的文件将被加密后的文件覆盖
            /// </summary>
            /// <param name="filePath"></param>
            public static void EncryptFile(string filePath)
            {
                EncryptFile(filePath, filePath);
            }

            /// <summary>
            /// 解密给定的字符串
            /// </summary>
            /// <param name="str">要解密的字符</param>
            /// <returns></returns>
            public static string DecryptString(string str)
            {
//                var des = new DESCryptoServiceProvider();
                int len = str.Length / 2;
	            var inputByteArray = new byte[len];
                int x;
                for (x = 0; x < len; x++)
	            {
	                int i = Convert.ToInt32(str.Substring(x * 2, 2), 16);
	                inputByteArray[x] = (byte)i;
	            }
                DES.Key = Encoding.ASCII.GetBytes(EncryptKey);
                DES.IV = Encoding.ASCII.GetBytes(Iv);
	            var ms = new MemoryStream();
                var cs = new CryptoStream(ms, DES.CreateDecryptor(), CryptoStreamMode.Write);
	            cs.Write(inputByteArray, 0, inputByteArray.Length);
	            cs.FlushFinalBlock();
	            return Encoding.Default.GetString(ms.ToArray());
            }
            /// <summary>
            /// 解密指定的文件
            /// </summary>
            /// <param name="filePath">要解密的文件路径</param>
            /// <param name="outPath">解密后的文件输出路径</param>
            public static void DecryptFile(string filePath, string outPath)
            {
                bool isExist = File.Exists(filePath);
                if (isExist)//如果存在
                {
                    byte[] ivb = Encoding.UTF8.GetBytes(Iv);
                    byte[] keyb = Encoding.UTF8.GetBytes(EncryptKey);
                    var file = new FileInfo(filePath);
                    var deCrypted = new byte[file.Length];
                    //得到要解密文件的字节流
                    var fin = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                    //解密文件

                    try
                    {
                        ICryptoTransform decryptor = DES.CreateDecryptor(keyb, ivb);
                        var csDecrypt = new CryptoStream(fin, decryptor, CryptoStreamMode.Read);
                        csDecrypt.Read(deCrypted, 0, deCrypted.Length);
                    }
                    catch (Exception err)
                    {
                        throw new ApplicationException(err.Message);
                    }
                    finally
                    {
                        fin.Close();
                    }
                    var fout = new FileStream(outPath, FileMode.Create, FileAccess.Write);
                    fout.Write(deCrypted, 0, deCrypted.Length);
                    fout.Close();
                }
                else
                {
                    throw new FileNotFoundException("指定的解密文件没有找到");
                }
            }
            /// <summary>
            /// 解密文件的重载版本,如果没有给出解密后文件的输出路径,
            /// 则解密后的文件将覆盖先前的文件
            /// </summary>
            /// <param name="filePath"></param>
            public static void DecryptFile(string filePath)
            {
                DecryptFile(filePath, filePath);
            }
            #endregion

        /// <summary>
        /// 从字符串中获取散列值
        /// </summary>
        /// <param name="str">要计算散列值的字符串</param>
        /// <returns></returns>

        public static string GetMD5FromString(string str)
        {
            byte[] toCompute = Encoding.Unicode.GetBytes(str);
            byte[] hashed = MD5.ComputeHash(toCompute, 0, toCompute.Length);
            return Encoding.ASCII.GetString(hashed);
        }
        /// <summary>
        /// 根据文件来计算散列值
        /// </summary>
        /// <param name="filePath">要计算散列值的文件路径</param>
        /// <returns></returns>
        public static string GetMD5FromFile(string filePath)
        {
            bool isExist = File.Exists(filePath);
            if (isExist)//如果文件存在
            {
                var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                var reader = new StreamReader(stream, Encoding.Unicode);
                string str = reader.ReadToEnd();
                byte[] toHash = Encoding.Unicode.GetBytes(str);
                byte[] hashed = MD5.ComputeHash(toHash, 0, toHash.Length);
                stream.Close();
                return Encoding.ASCII.GetString(hashed);
            }
            throw new FileNotFoundException("指定的文件没有找到");
        }
      
        /// <summary>
        /// 用于数字签名的hash类
        /// </summary>
        public class MACTripleDESEncrypt
        {
            private static MACTripleDES _mact;
            private static string _key = "ksn168ch";

            public  MACTripleDESEncrypt()
            {
                _mact = new MACTripleDES();
            }
            /// <summary>
            /// 获取或设置用于数字签名的密钥
            /// </summary>
            public static string Key
            {
                get { return _key; }
                set
                {
                    int keyLength = value.Length;
                    var keyAllowLengths = new[] { 8, 16, 24 };
                    bool isRight = keyAllowLengths.Any(i => keyLength == keyAllowLengths[i]);
                    if (!isRight)
                        throw new ApplicationException("用于数字签名的密钥长度必须是8,16,24值之一");
                    _key = value;
                }
            }

            /// <summary>
            /// 获取或设置用于数字签名的用户数据
            /// </summary>
            public static byte[] Data { get; set; }

            /// <summary>
            /// 得到签名后的hash值
            /// </summary>
            /// <returns></returns>
            public static string GetHashValue()
            {
                if (Data == null)
                    throw new Exception("没有设置要进行数字签名的用户" +"数据(property:Data)");
                byte[] key = Encoding.UTF8.GetBytes(Key);
                _mact.Key = key;
                byte[] hashB = _mact.ComputeHash(_mact.ComputeHash(Data));
                return Encoding.UTF8.GetString(hashB);
            }
        }
    }
}